package com.ziven.processor;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;

/**
 * @author Ziven
 */
public class LearnProcessor extends AbstractProcessor {

    public static final String CLASS_NAME = "LearnFactory";

    protected Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if(set == null || set.isEmpty() || roundEnvironment == null) {
            return false;
        }
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Learn.class);
        if(elements == null || elements.isEmpty()) {
            return false;
        }

        ParameterizedTypeName typeName = ParameterizedTypeName.get(ClassName.get(ArrayList.class), ClassName.get(LearnBaseBean.class));
        MethodSpec.Builder method = MethodSpec.methodBuilder("create")
                .addAnnotation(Override.class)
                .returns(typeName)
                .addModifiers(Modifier.PUBLIC)
                .addStatement("$T learn = new $T()", typeName, typeName);

        for (Element element : elements) {
            method.addStatement("learn.add(new LearnBaseBean(new $L(), $S))", element.asType(), element.getAnnotation(Learn.class).learn());
        }
        method.addStatement("return learn");

        TypeSpec.Builder cls = TypeSpec.classBuilder(CLASS_NAME)
                .addModifiers(Modifier.PUBLIC)
                .addJavadoc("DO NOT MODIFY")
                .addSuperinterface(LearnCreate.class)
                .addMethod(method.build());

        try {
            JavaFile.builder("com.ziven.processor", cls.build()).build().writeTo(filer);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotation = new LinkedHashSet<>();
        annotation.add(Learn.class.getCanonicalName());
        return annotation;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}